package plus.easydo.starter.oauth.core.utils;

import cn.hutool.core.bean.BeanUtil;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import plus.easydo.starter.oauth.core.model.CustomizeUsernamePasswordAuthenticationToken;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author yuzhanfeng
 */
public class Oauth2Utils {

    private static final String ADMIN = "admin";

    private static final Map<String,Object> anonymousUser = new HashMap<>();

    static {
        anonymousUser.put("username","anonymousUser");
        anonymousUser.put("id","-1");
    }


    private Oauth2Utils() {
    }

    public static Map<String, Object> getUserInfo() {
        Authentication authentication = getOauth2Authentication();
        if(Objects.nonNull(authentication)){
            Object user =  authentication.getPrincipal();
            if (user instanceof Map){
                return (Map<String, Object>) user;
            }else if(user instanceof String){
                return anonymousUser;
            }
            return BeanUtil.beanToMap(user);
        }
        return anonymousUser;
    }

    public static String getUserName() {
        Map<String, Object> userMap = getUserInfo();
        return (String) userMap.get("username");
    }

    public static Long getUserIdLong() {
        Map<String, Object> userMap = getUserInfo();
        Object id = userMap.get("id");
        if (id instanceof Integer) {
            return Long.parseLong(id.toString());
        } else if (id instanceof Long) {
            return (Long) id;
        } else if (id instanceof String) {
            return Long.parseLong((String) id);
        } else {
            return null;
        }
    }

    public static String getUserIdString() {
        Map<String, Object> userMap = getUserInfo();
        Object id = userMap.get("id");
        return String.valueOf(id);
    }

    public static String getTenantId() {
        Map<String, Object> userMap = getUserInfo();
        return (String) userMap.get("tenantId");
    }

    public static Integer getUserIdInteger() {
        Map<String, Object> userMap = getUserInfo();
        Object id = userMap.get("id");
        if (id instanceof Integer) {
            return (Integer) id;
        } else if (id instanceof Long) {
            return ((Long) id).intValue();
        } else if (id instanceof String) {
            return Integer.parseInt((String) id);
        } else {
            return null;
        }
    }

    public static Object getUserId() {
        Map<String, Object> userMap = getUserInfo();
        return userMap.get("id");
    }

    public static Object getUserValue(String key) {
        Map<String, Object> map = getUserInfo();
        return map.get(key);
    }

    public static Set<String> getRoles() {
        return getOauth2Authentication().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
    }

    public static Collection<?> getPermissions() {
        Authentication authentication = getUserAuthentication();
        if (authentication instanceof CustomizeUsernamePasswordAuthenticationToken) {
            return ((CustomizeUsernamePasswordAuthenticationToken)authentication).getPermissions();
        }
        return authentication.getAuthorities();
    }

    public static String getClientId() {
        OAuth2Request oauth2Request = getOauth2Request();
        if (Objects.nonNull(oauth2Request)){
            return oauth2Request.getClientId();
        }
        return "";
    }

    public static String getTokenValue() {
        Object details = getDetails();
        if(details instanceof OAuth2AuthenticationDetails){
            return ((OAuth2AuthenticationDetails) details).getTokenValue();
        }
        return "";
    }

    public static String getTokenType() {
        Object details = getDetails();
        if(details instanceof OAuth2AuthenticationDetails){
            return ((OAuth2AuthenticationDetails) details).getTokenType();
        }
        return "";
    }

    public static Set<String> getResourceIds() {
        OAuth2Request oauth2Request = getOauth2Request();
        if (Objects.nonNull(oauth2Request)){
            return oauth2Request.getResourceIds();
        }
        return Collections.emptySet();
    }

    public static Set<String> getScope() {
        OAuth2Request oauth2Request = getOauth2Request();
        if (Objects.nonNull(oauth2Request)){
            return oauth2Request.getScope();
        }
        return Collections.emptySet();
    }

    public static String getRedirectUri() {
        OAuth2Request oauth2Request = getOauth2Request();
        if (Objects.nonNull(oauth2Request)){
            return oauth2Request.getRedirectUri();
        }
        return "";
    }

    public static Object getDetails() {
        return getOauth2Authentication().getDetails();
    }

    public static Authentication getOauth2Authentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    public static Authentication getUserAuthentication() {
        Authentication authentication = getOauth2Authentication();
        if(authentication instanceof OAuth2Authentication){
            Authentication userAuthentication = ((OAuth2Authentication) authentication).getUserAuthentication();
            if(userAuthentication instanceof CustomizeUsernamePasswordAuthenticationToken){
                return userAuthentication;
            }
        }
        return authentication;
    }

    public static OAuth2Request getOauth2Request() {
        Authentication authentication = getOauth2Authentication();
        if (authentication instanceof OAuth2Authentication){
            return ((OAuth2Authentication) authentication).getOAuth2Request();
        }
        return null;
    }

    /**
     * 是否为管理员
     *
     * @param userId 用户ID
     * @return 结果
     */
    public static boolean isAdmin(Long userId) {
        return userId != null && 1L == userId;
    }

    /**
     * 是否为管理员
     *
     * @return 结果
     */
    public static boolean isAdmin() {
        return getRoles().contains(ADMIN);
    }

    /**
     * 生成BCryptPasswordEncoder密码
     *
     * @param password 密码
     * @return 加密字符串
     */
    public static String encryptPassword(String password) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.encode(password);
    }

    /**
     * 判断密码是否相同
     *
     * @param rawPassword     真实密码
     * @param encodedPassword 加密后字符
     * @return 结果
     */
    public static boolean matchesPassword(String rawPassword, String encodedPassword) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

}
